package com.yc.projects.pro5_mySpring.org.springframework.context;

import com.yc.projects.pro5_mySpring.org.springframework.annotation.*;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class YcAnnotationConfigApplicationContext<T> implements YcApplicationContext<T> {
    private Map<String, Object> beanMap = new ConcurrentHashMap<>();
    private Map<String, YcBeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    public YcAnnotationConfigApplicationContext(Class<?>... componentClass) {
        for (Class cls : componentClass) {
            // 1. 解析配置类中的@Bean注解
            parseBeanAnnotation(cls);
            // 2. 扫描包路径
            if (cls.isAnnotationPresent(YcComponentScan.class)) {
                YcComponentScan ycComponentScan = (YcComponentScan) cls.getAnnotation(YcComponentScan.class);
                //这个是看value的值有没有
                String[] basePackages = ycComponentScan.value();
                //如果没有设置value，就用basePackages
                if (basePackages == null || basePackages.length == 0) {
                    basePackages = ycComponentScan.basePackages();
                }
                //如果没有设置basePackages，就用cls的包路径
                if (basePackages == null || basePackages.length == 0) {
                    basePackages = new String[1];
                    basePackages[0] = cls.getPackage().getName();
                }
                for (String basePackage : basePackages) {
                    System.out.println(basePackage);
                }
                //递归扫描
                recursiveLoadBeanDefinition(basePackages);
                // 3. 注册beanDefinition
                // 4. 创建单例bean(ioc)
                // 5. 注入属性(di)
            }
        }
    }

    private void recursiveLoadBeanDefinition(String[] basePackages) {
        for (String basePackage : basePackages) {
            // 将包名转换为文件路径
            String packagePath = basePackage.replace('.', '/');
            try {
                // 获取当前包下的所有类文件
                Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packagePath);
                while (resources.hasMoreElements()) {
                    URL resource = resources.nextElement();
                    System.out.println("正在扫描的包下的路径为" + resource.getFile());
                    if ("file".equals(resource.getProtocol())) {
                        // 如果是文件系统下的路径
                        File packageDir = new File(resource.getFile());
                        if (packageDir.isDirectory()) {
                            // 遍历目录下的所有文件
                            scanClasses(basePackage, packageDir);
                        }
                    } else if ("jar".equals(resource.getProtocol())) {
                        // 如果是 jar 包路径
                        scanJar(basePackage, resource);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 处理文件系统下的类文件
    private void scanClasses(String basePackage, File packageDir) {
        File[] files = packageDir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    System.out.println("子包为" + file.getName());
                    // 递归处理子目录
                    scanClasses(basePackage + "." + file.getName(), file);
                } else if (file.getName().endsWith(".class")) {
                    System.out.println("字节码文件为" + file.getName());
                    getBeanDefinition(basePackage, file);
                }
            }
        }
    }

    private void getBeanDefinition(String basePackage, File file) {
        try {
            // 获取类名，去掉 ".class" 后缀
            String className = basePackage + '.' + file.getName().substring(0, file.getName().length() - 6);
            Class<?> cls = Class.forName(className);
         // 解析注解等
            if (cls.isAnnotationPresent(YcComponent.class) ||
                    cls.isAnnotationPresent(YcRepository.class) ||
                    cls.isAnnotationPresent(YcService.class) ||
                    cls.isAnnotationPresent(YcController.class)
            ) {
                YcBeanDefinition bd = new YcBeanDefinition();
                if (cls.isAnnotationPresent(YcLazy.class)) {
                    YcLazy lazy = cls.getAnnotation(YcLazy.class);
                    bd.setLazy(lazy.value());
                } else {
                    bd.setLazy(false);
                }
                if (cls.isAnnotationPresent(YcScope.class)) {
                    YcScope ycScope = cls.getAnnotation(YcScope.class);
                    bd.setScope(ycScope.value());
                } else {
                    bd.setScope("singleton");
                }
                bd.setClassInfo(cls.getName());
                String beanName=getBeanName(cls);
                beanDefinitionMap.put(beanName, bd);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private String getBeanName(Class<?> cls) {
        String beanName = "";
        YcComponent ycComponent=cls.getAnnotation(YcComponent.class);
        if (ycComponent != null) {
            beanName = ycComponent.value();
        }
        YcRepository ycRepository = cls.getAnnotation(YcRepository.class);
        if (ycRepository != null) {
            beanName = ycRepository.value();
        }
        YcService ycService = cls.getAnnotation(YcService.class);
        if (ycService != null) {
            beanName = ycService.value();
        }
        YcController ycController = cls.getAnnotation(YcController.class);
        if (ycController != null) {
            beanName = ycController.value();
        }
        if (beanName.isEmpty()) {
            beanName = cls.getSimpleName();
            beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
        }
        return beanName;
    }

    // 处理 jar 包中的类文件
    private void scanJar(String basePackage, URL resource) {
        try (JarFile jarFile = ((JarURLConnection) resource.openConnection()).getJarFile()) {
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName();
                if (entryName.endsWith(".class")) {
                    // 将类名转换为包路径格式
                    String className = entryName.substring(0, entryName.length() - 6).replace('/', '.');
                    if (className.startsWith(basePackage)) {
                        try {
                            Class<?> cls = Class.forName(className);
                            // parseBeanAnnotation(cls); // 解析 @YcBean 注解等
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void parseBeanAnnotation(Class cls) {
        try {
            Constructor<?> constructor = cls.getDeclaredConstructor();
            Object obj = constructor.newInstance();

//            Object obj = cls.newInstance();
            String clzName = cls.getSimpleName();
            YcBeanDefinition bd = new YcBeanDefinition();

            //固定值暂时写死
            bd.setLazy(false);
            bd.setScope("singleton");

            bd.setClassInfo(cls.getName());
            String beanName = clzName.substring(0, 1).toLowerCase() + clzName.substring(1);

            beanDefinitionMap.put(beanName, bd);
            beanMap.put(beanName, obj);

            Method[] ms = cls.getDeclaredMethods();
            for (Method m : ms) {
                if (m.isAnnotationPresent(YcBean.class)) {
                    YcBean ycBean = m.getAnnotation(YcBean.class);
                    String ycBeanName = ycBean.value();
                    if (ycBeanName.equals("")) {
                        ycBeanName = m.getName();
                    }
                    //o就是对象
                    Object o = m.invoke(obj, null);
                    YcBeanDefinition bd1 = new YcBeanDefinition();
                    beanMap.put(ycBeanName, o);
                    bd1.setClassInfo(cls.getName());
                    bd1.setLazy(false);
                    bd1.setScope("singleton");

                    beanDefinitionMap.put(ycBeanName, bd1);
                }
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object getBean(String beanName) {
        return null;
    }

    @Override
    public T getBean(Class<T> type) {
        return null;
    }

    @Override
    public T getBean(String beanName, Class<T> type) {
        return null;
    }


}
